//
// CommandWrapper
//
// Copyright (C) jextra.net.
//
//  This file is part of the Crack build system.
//
//  The Crack build system is free software; you can redistribute it 
//  and/or modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  The Crack build system is distributed in the hope that it will be 
//  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with the Crack build system; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//  02111-1307 USA.
//

package net.jextra.crack.core;

import java.lang.reflect.*;
import java.util.*;
import net.jextra.crack.*;

/**
 * <p>
 * Wrapper for a command method. It contains a field to the instance that contains the command method, the Method
 * itself, the {@link CrackCommand} annotation associated with the Method as well as a map of the "CommandRegistration".
 * A typical command method looks like this:
 * </p>
 * 
 * <pre>
 * &#064;CrackCommand( description = &quot;Run Program&quot; )
 * public void run()
 * {
 *     // Do whatever.
 * }
 * </pre>
 */
public class CommandWrapper
{
    // ============================================================
    // Fields
    // ============================================================

    private Object knob;
    private Method method;
    // Keeps priority order versus keys in _registrations map.
    private ArrayList<String> names;
    private LinkedHashMap<String, CommandRegistration> registrations;
    private CrackCommand annotation;
    private ArrayList<CommandArg> args;

    // ============================================================
    // Constructors
    // ============================================================

    public CommandWrapper( Object knob, Method method, CrackCommand annotation )
    {
        this.knob = knob;
        this.method = method;
        this.annotation = annotation;
        names = new ArrayList<String>();
        registrations = new LinkedHashMap<String, CommandRegistration>();
        args = new ArrayList<CommandArg>();
    }

    // ============================================================
    // Methods
    // ============================================================

    // ----------
    // public
    // ----------

    /**
     * Return the first name registered for this wrapper.
     */
    public String getName()
    {
        registrations.keySet().iterator().next();
        return names.get( 0 );
    }

    public Object getCommandsKnob()
    {
        return knob;
    }

    public void setCommandsKnob( Object knob )
    {
        this.knob = knob;
    }

    public Method getMethod()
    {
        return method;
    }

    public void setMethod( Method method )
    {
        this.method = method;
    }

    public CrackCommand getAnnotation()
    {
        return annotation;
    }

    public void setAnnotation( CrackCommand annotation )
    {
        this.annotation = annotation;
    }

    public void addRegistration( CommandRegistration reg )
    {
        names.add( reg.getName() );
        registrations.put( reg.getName(), reg );
    }

    public CommandRegistration getRegistration( String name )
    {
        return registrations.get( name );
    }

    public CommandRegistration removeRegistration( String name )
    {
        CommandRegistration reg = registrations.get( name );
        names.remove( name );
        registrations.remove( name );
        return reg;
    }

    public void renameRegistration( String oldName, String newName )
    {
        int index = names.indexOf( oldName );
        names.set( index, newName );

        CommandRegistration reg = registrations.get( oldName );
        reg.setName( newName );
        registrations.remove( oldName );
        registrations.put( newName, reg );
    }

    public Collection<CommandRegistration> getRegistrations()
    {
        return registrations.values();
    }

    public void addArg( CommandArg arg )
    {
        args.add( arg );
    }

    public List<CommandArg> getArgs()
    {
        return args;
    }

    // ============================================================
    // Inner Classes
    // ============================================================

    /**
     * Registered namespace name in the CrackBuild and attributes about the command.
     */
    public static class CommandRegistration
    {
        private String _name;
        private boolean _visible;

        public CommandRegistration( String name, boolean visible )
        {
            _name = name;
            _visible = visible;
        }

        public String getName()
        {
            return _name;
        }

        public void setName( String name )
        {
            _name = name;
        }

        public boolean isVisible()
        {
            return _visible;
        }

        public void setVisible( boolean visible )
        {
            _visible = visible;
        }
    }

    public static class CommandArg
    {
        private String _name;
        private String _description;
        private Class<?> _type;

        public CommandArg( String name, String description, Class<?> type )
        {
            _name = name;
            _description = description;
            _type = type;
        }

        public String getName()
        {
            return _name;
        }

        public void setName( String name )
        {
            _name = name;
        }

        public String getDescription()
        {
            return _description;
        }

        public void setDescription( String description )
        {
            _description = description;
        }

        public Class<?> getType()
        {
            return _type;
        }

        public void setType( Class<?> type )
        {
            _type = type;
        }
    }
}
